using System;
using Sys;
using System.DHTML;
using Sys.UI;
using Sys.Mvc;

using JQuerySharp;

[Record]
[IgnoreNamespace]
public sealed class LoadCallbackInfo
{
    public string ControllerAction;
    public Callback Callback;

    public LoadCallbackInfo(string controllerAction, Callback callback)
    {
        ControllerAction = controllerAction;
        Callback = callback;
    }
}

static public partial class LoadHelper
{
    static MvcAsyRequestDelegate s_mvcHandleClick;
    static MvcAsyRequestDelegate s_mvcHandleSubmit;
    static bool s_isAppLoaded = false;
    public static Callback[] s_LoadCallbackList = new Callback[0];
    static LoadCallbackInfo[] s_AsynActionLoadCallbackList = new LoadCallbackInfo[0];

    static LoadHelper()
    {
        Application.Init += new EventHandler(delegate(object sender, EventArgs e)
                                                {
                                                    s_isAppLoaded = true;
                                                    RunLoadCallback();
                                                });

        s_mvcHandleClick = AsyncHyperlink.HandleClick;
        Type.SetField(typeof(AsyncHyperlink), "handleClick", new MvcAsyRequestDelegate(HandleClick));
        s_mvcHandleSubmit = AsyncForm.HandleSubmit;
        Type.SetField(typeof(AsyncForm), "handleSubmit", new MvcAsyRequestDelegate(HandleSubmit));
    }

    static void RunLoadCallback()
    {
        if (!s_isAppLoaded)
        {
            return;
        }

        //Run LoadCallback - FIFO
        int count = s_LoadCallbackList.Length;
        for (int i = 0; i < count; i++)
        {
            Callback callback = s_LoadCallbackList[0];
            if (callback != null)
            {
                callback();
            }

            try
            {
                Type.InvokeMethod(s_LoadCallbackList, "remove", s_LoadCallbackList[0]);    
            }
            catch
            {
            }
            
        }
        //Debug.Assert(s_LoadCallbackList.Length == 0);
    }

    static public void RunAsynLoadCallback(string url)
    {
        if (!s_isAppLoaded)
        {
            return;
        }

        string controllerAction = Utils.GetController(url) + "/" + Utils.GetAction(url);
        if (controllerAction == null || controllerAction.Length == 0)
        {
            controllerAction = "Home/Index";
        }
        if (controllerAction.IndexOf('/') < 0)
        {
            controllerAction += "/Index";
        }

        int count = s_AsynActionLoadCallbackList.Length;
        for (int i = 0; i < count; i++)
        {
            LoadCallbackInfo callbackInfo = s_AsynActionLoadCallbackList[i];
            if (callbackInfo != null && callbackInfo.Callback != null
                && callbackInfo.ControllerAction != null
                && controllerAction.ToLowerCase() == callbackInfo.ControllerAction.ToLowerCase())
            {
                callbackInfo.Callback();
            }
        }
    }

    static public void RegisterLoadCallback(Callback loadCallback)
    {
        if (loadCallback != null)
        {
            s_LoadCallbackList[s_LoadCallbackList.Length] = loadCallback;
        }
        RunLoadCallback();
    }

    static public void RegisterLoad(Callback loadCallback)
    {
        RegisterLoadCallback(loadCallback);
    }

    static public void RegisterAsynActionLoad(string controllerAction, Callback loadCallback)
    {
        if (loadCallback != null && controllerAction != null && loadCallback != null)
        {
            s_AsynActionLoadCallbackList[s_AsynActionLoadCallbackList.Length] = new LoadCallbackInfo(controllerAction, loadCallback);
        }
    }

    static void HandleClick(Dictionary source, DomEvent eventSource, Dictionary ajaxOption)
    {
        AjaxOptions option = (AjaxOptions)(object)ajaxOption;
        MvcCallback oldDelegate = option.OnSuccess;
        option.OnSuccess = new MvcCallback(delegate(AjaxContext context)
                                            {
                                                RunLoadCallback();
                                                string url = context.request.GetResolvedUrl();
                                                RunAsynLoadCallback(url);
                                                RunScript(option);
                                                if (oldDelegate != null)
                                                {
                                                    oldDelegate(context);
                                                }

                                            });
        s_mvcHandleClick(source, eventSource, ajaxOption);
    }

    static void HandleSubmit(Dictionary source, DomEvent eventSource, Dictionary ajaxOption)
    {
        AjaxOptions option = (AjaxOptions)(object)ajaxOption;
        MvcCallback oldDelegate = option.OnSuccess;
        option.OnSuccess = new MvcCallback(delegate(AjaxContext context)
                                            {
                                                string url = context.request.GetResolvedUrl();
                                                RunAsynLoadCallback(url);
                                                RunScript(option);
                                                if (oldDelegate != null)
                                                {
                                                    oldDelegate(context);
                                                }
                                            });
        s_mvcHandleSubmit(source, eventSource, ajaxOption);
    }

    static void RunScript(AjaxOptions option)
    {
        string updateId = option.UpdateTargetId;
        if (updateId == null || updateId == "") return;
        RunScriptInElement(updateId);
    }

    static public void RunScriptInElement(string elId)
    {
        if (elId == null || elId == "") return;
        string selector = string.Format("#{0} script", elId);
        jQuery query = JQueryFactory.JQuery(selector);
        ScriptElement[] scriptEls = (ScriptElement[])(object)query;
        string scriptText = "";
        for (int i = 0; i < scriptEls.Length; i++)
        {
            scriptText += scriptEls[i].InnerHTML + "\r\n";
        }
        if (scriptText != "")
        {
            //Script.Alert(scriptText);
            Script.Eval(scriptText);
        }
    }

}
